using System;
using System.Data;
using System.IO;
using System.Collections.Generic;
using TALoaders;
using PortfolioAllocator.Optimization;
using PortfolioAllocator.GUI;

namespace PortfolioAllocator.Tests
{
    using NUnit.Framework;

    [TestFixture]
    class TestOptimizationRunner
    {
        [Test]
        [Category("Calculation")]
        public void runMinVar()
        {
            DataTable dTable = this.createEmptyDataTable();
            // row 1
            DataRow row = dTable.NewRow();
            row[PortfolioAllocatorWindow.LOADER_COL] = Loader.Test;
            row[PortfolioAllocatorWindow.TICKER_COL] = "RX1 Index";
            row[PortfolioAllocatorWindow.EXP_RET_COL] = 0.13;
            row[PortfolioAllocatorWindow.MIN_WEIGHT_COL] = 0.1;
            row[PortfolioAllocatorWindow.MAX_WEIGHT_COL] = 0.9;
            dTable.Rows.Add(row);
            // row 2
            row = dTable.NewRow();
            row[PortfolioAllocatorWindow.LOADER_COL] = Loader.Test;
            row[PortfolioAllocatorWindow.TICKER_COL] = "OMX Index";
            row[PortfolioAllocatorWindow.EXP_RET_COL] = 0.17;
            row[PortfolioAllocatorWindow.MIN_WEIGHT_COL] = 0.0;
            row[PortfolioAllocatorWindow.MAX_WEIGHT_COL] = 1.0;
            dTable.Rows.Add(row);

            DateTime start = new DateTime(2010, 1, 1);
            DateTime end = new DateTime(2010, 5, 1);

            OptimizationRunner runner = new OptimizationRunner();
            List<OptimizationRunner.PConstraint> constraints = new List<OptimizationRunner.PConstraint>();
            DataTable outTable = runner.runMinVarianceAnalysis(dTable, start, end, constraints);

            string tmpFileName = "tmpMinVarResult.csv";
            string expFileName = "..\\..\\Tests\\MinVarResult.csv";
            TALoaders.Utilities.saveDataTableToCSV(tmpFileName, outTable);
            FileAssert.AreEqual(expFileName, tmpFileName, "Optimization runner outTable");
            File.Delete(tmpFileName);
        }

        [Test]
        [Category("Calculation")]
        public void runMinVarBT()
        {
            DataTable dTable = this.createEmptyDataTable();
            // row 1
            DataRow row = dTable.NewRow();
            row[PortfolioAllocatorWindow.LOADER_COL] = Loader.Test;
            row[PortfolioAllocatorWindow.TICKER_COL] = "RX1 Index";
            row[PortfolioAllocatorWindow.EXP_RET_COL] = 0.13;
            row[PortfolioAllocatorWindow.MIN_WEIGHT_COL] = 0.1;
            row[PortfolioAllocatorWindow.MAX_WEIGHT_COL] = 0.9;
            dTable.Rows.Add(row);
            // row 2
            row = dTable.NewRow();
            row[PortfolioAllocatorWindow.LOADER_COL] = Loader.Test;
            row[PortfolioAllocatorWindow.TICKER_COL] = "OMX Index";
            row[PortfolioAllocatorWindow.EXP_RET_COL] = 0.27;
            row[PortfolioAllocatorWindow.MIN_WEIGHT_COL] = 0.0;
            row[PortfolioAllocatorWindow.MAX_WEIGHT_COL] = 1.0;
            dTable.Rows.Add(row);
            // row 3
            row = dTable.NewRow();
            row[PortfolioAllocatorWindow.LOADER_COL] = Loader.Test;
            row[PortfolioAllocatorWindow.TICKER_COL] = "DAX Index";
            row[PortfolioAllocatorWindow.EXP_RET_COL] = 0.15;
            row[PortfolioAllocatorWindow.MIN_WEIGHT_COL] = 0.0;
            row[PortfolioAllocatorWindow.MAX_WEIGHT_COL] = 1.0;
            dTable.Rows.Add(row);

            DateTime start = new DateTime(2010, 1, 1);
            DateTime end = new DateTime(2010, 5, 1);

            List<OptimizationRunner.PConstraint> constraints = new List<OptimizationRunner.PConstraint>();
            constraints.Add(new OptimizationRunner.PConstraint(0, 0.2, new string[] { "RX1 Index", "OMX Index" }));

            OptimizationRunner runner = new OptimizationRunner();
            DataTable outTable = runner.runMinVarBackTest(dTable, start, end, constraints);

            string tmpFileName = "tmpMinVarBT.csv";
            string expFileName = "..\\..\\Tests\\MinVarBT.csv";
            TALoaders.Utilities.saveDataTableToCSV(tmpFileName, outTable);
            FileAssert.AreEqual(expFileName, tmpFileName, "Optimization runner outTable");
            File.Delete(tmpFileName);
        }

        [Test]
        [Category("Calculation")]
        public void runMinVarBTSingleInstr()
        {
            DataTable dTable = this.createEmptyDataTable();
            // row 1
            DataRow row = dTable.NewRow();
            row[PortfolioAllocatorWindow.LOADER_COL] = Loader.Test;
            row[PortfolioAllocatorWindow.TICKER_COL] = "RX1 Index";
            row[PortfolioAllocatorWindow.EXP_RET_COL] = 0.13;
            row[PortfolioAllocatorWindow.MIN_WEIGHT_COL] = 0.0;
            row[PortfolioAllocatorWindow.MAX_WEIGHT_COL] = 1.0;
            dTable.Rows.Add(row);

            DateTime start = new DateTime(2010, 1, 1);
            DateTime end = new DateTime(2010, 5, 1);

            List<OptimizationRunner.PConstraint> constraints = new List<OptimizationRunner.PConstraint>();

            OptimizationRunner runner = new OptimizationRunner();
            DataTable outTable = runner.runMinVarBackTest(dTable, start, end, constraints);

            string tmpFileName = "tmpMinVarBTSingle.csv";
            string expFileName = "..\\..\\Tests\\MinVarBTSingle.csv";
            TALoaders.Utilities.saveDataTableToCSV(tmpFileName, outTable);
            FileAssert.AreEqual(expFileName, tmpFileName, "Optimization runner outTable");
            File.Delete(tmpFileName);
        }

        [Test]
        [Category("Calculation")]
        public void runMinVarWithConstraints()
        {
            CachedDownloader.clearCache();
            DataTable dTable = this.createEmptyDataTable();
            // row 1
            DataRow row = dTable.NewRow();
            row[PortfolioAllocatorWindow.LOADER_COL] = Loader.Test;
            row[PortfolioAllocatorWindow.TICKER_COL] = "RX1 Index";
            row[PortfolioAllocatorWindow.EXP_RET_COL] = 0.13;
            row[PortfolioAllocatorWindow.MIN_WEIGHT_COL] = 0.1;
            row[PortfolioAllocatorWindow.MAX_WEIGHT_COL] = 0.9;
            dTable.Rows.Add(row);
            // row 2
            row = dTable.NewRow();
            row[PortfolioAllocatorWindow.LOADER_COL] = Loader.Test;
            row[PortfolioAllocatorWindow.TICKER_COL] = "OMX Index";
            row[PortfolioAllocatorWindow.EXP_RET_COL] = 0.27;
            row[PortfolioAllocatorWindow.MIN_WEIGHT_COL] = 0.0;
            row[PortfolioAllocatorWindow.MAX_WEIGHT_COL] = 1.0;
            dTable.Rows.Add(row);
            // row 3
            row = dTable.NewRow();
            row[PortfolioAllocatorWindow.LOADER_COL] = Loader.Test;
            row[PortfolioAllocatorWindow.TICKER_COL] = "DAX Index";
            row[PortfolioAllocatorWindow.EXP_RET_COL] = 0.15;
            row[PortfolioAllocatorWindow.MIN_WEIGHT_COL] = 0.0;
            row[PortfolioAllocatorWindow.MAX_WEIGHT_COL] = 1.0;
            dTable.Rows.Add(row);

            DateTime start = new DateTime(2010, 1, 1);
            DateTime end = new DateTime(2010, 5, 1);

            List<OptimizationRunner.PConstraint> constraints = new List<OptimizationRunner.PConstraint>();
            constraints.Add(new OptimizationRunner.PConstraint(0,0.2, new string[] {"RX1 Index", "OMX Index"}));

            OptimizationRunner runner = new OptimizationRunner();
            DataTable outTable = runner.runMinVarianceAnalysis(dTable, start, end, constraints);

            string tmpFileName = "tmpMinVarResultWithConstr.csv";
            string expFileName = "..\\..\\Tests\\MinVarResultWithConstr.csv";
            TALoaders.Utilities.saveDataTableToCSV(tmpFileName, outTable);
            FileAssert.AreEqual(expFileName, tmpFileName, "Optimization runner outTable");
            File.Delete(tmpFileName);
        }

        [Test]
        [Category("Calculation")]
        public void runMinVarWrongConstraint()
        {
            DataTable dTable = this.createEmptyDataTable();
            // row 1
            DataRow row = dTable.NewRow();
            row[PortfolioAllocatorWindow.LOADER_COL] = Loader.Test;
            row[PortfolioAllocatorWindow.TICKER_COL] = "RX1 Index";
            row[PortfolioAllocatorWindow.EXP_RET_COL] = 0.13;
            row[PortfolioAllocatorWindow.MIN_WEIGHT_COL] = 0.1;
            row[PortfolioAllocatorWindow.MAX_WEIGHT_COL] = 0.9;
            dTable.Rows.Add(row);
            // row 2
            row = dTable.NewRow();
            row[PortfolioAllocatorWindow.LOADER_COL] = Loader.Test;
            row[PortfolioAllocatorWindow.TICKER_COL] = "OMX Index";
            row[PortfolioAllocatorWindow.EXP_RET_COL] = 0.27;
            row[PortfolioAllocatorWindow.MIN_WEIGHT_COL] = 0.0;
            row[PortfolioAllocatorWindow.MAX_WEIGHT_COL] = 1.0;
            dTable.Rows.Add(row);
 
            DateTime start = new DateTime(2010, 1, 1);
            DateTime end = new DateTime(2010, 5, 1);

            List<OptimizationRunner.PConstraint> constraints = new List<OptimizationRunner.PConstraint>();
            constraints.Add(new OptimizationRunner.PConstraint(0, 0.2, new string[] { "DAX Index", "OMX Index" }));

            OptimizationRunner runner = new OptimizationRunner();
            DataTable outTable = runner.runMinVarianceAnalysis(dTable, start, end, constraints);

            string tmpFileName = "tmpMinVarWrongConstr.csv";
            string expFileName = "..\\..\\Tests\\MinVarWrongConstr.csv";
            TALoaders.Utilities.saveDataTableToCSV(tmpFileName, outTable);
            FileAssert.AreEqual(expFileName, tmpFileName, "Optimization runner outTable");
            File.Delete(tmpFileName);
        }

        [Test]
        [Category("Calculation")]
        public void runMinVarOnYahooData()
        {
            DataTable dTable = this.createTableFromCSV("Test-Constituents.csv");
            
            DateTime start = new DateTime(2010, 1, 1);
            DateTime end = new DateTime(2010, 5, 1);

            // No Constraints
            OptimizationRunner runner = new OptimizationRunner();
            List<OptimizationRunner.PConstraint> constraints = new List<OptimizationRunner.PConstraint>();
            DataTable outTable = runner.runMinVarianceAnalysis(dTable, start, end, constraints);

            string tmpFileName = "tmpMinVarResultOnYahoo.csv";
            string expFileName = "..\\..\\Tests\\MinVarResultOnYahoo.csv";
            TALoaders.Utilities.saveDataTableToCSV(tmpFileName, outTable);
            FileAssert.AreEqual(expFileName, tmpFileName, "Optimization runner outTable");
            File.Delete(tmpFileName);

            // Add Constraints on OMX+DAX, OMX+UCD
            constraints.Add(new OptimizationRunner.PConstraint(0, 0.2, new string[] { "^OMX", "^GDAXI" }));
            constraints.Add(new OptimizationRunner.PConstraint(0.1, 0.3, new string[] { "^OMX", "UCD" }));
            outTable = runner.runMinVarianceAnalysis(dTable, start, end, constraints);
            tmpFileName = "tmpMinVarResultOnYahooWithConstr.csv";
            expFileName = "..\\..\\Tests\\MinVarResultOnYahooWithConstr.csv";
            TALoaders.Utilities.saveDataTableToCSV(tmpFileName, outTable);
            FileAssert.AreEqual(expFileName, tmpFileName, "Optimization runner outTable with Constraints");
            File.Delete(tmpFileName);
        }

        [Test]
        [Category("Calculation")]
        public void runMinVarBTOnYahooData()
        {
            DataTable dTable = this.createTableFromCSV("Test-Constituents.csv");

            DateTime start = new DateTime(2010, 1, 5);
            DateTime end = new DateTime(2010, 5, 1);

            OptimizationRunner runner = new OptimizationRunner();
            List<OptimizationRunner.PConstraint> constraints = new List<OptimizationRunner.PConstraint>();
            // Add Constraints on OMX+DAX, OMX+UCD
            constraints.Add(new OptimizationRunner.PConstraint(0, 0.9, new string[] { "^OMX", "^GDAXI" }));
            constraints.Add(new OptimizationRunner.PConstraint(0.1, 0.8, new string[] { "^OMX", "UCD" }));
            DataTable outTable = runner.runMinVarBackTest(dTable, start, end, constraints);
            string tmpFileName = "tmpMinVarBTYahoo.csv";
            string expFileName = "..\\..\\Tests\\MinVarBTYahoo.csv";
            TALoaders.Utilities.saveDataTableToCSV(tmpFileName, outTable);
            FileAssert.AreEqual(expFileName, tmpFileName, "Optimization runner outTable with Constraints");
            File.Delete(tmpFileName);
        }

        [Test]
        [Category("Calculation")]
        public void runMinVarBTOnCommodityETF()
        {
            DataTable dTable = this.createTableFromCSV("CommodityETFs.csv");

            DateTime start = new DateTime(2009, 1, 4);
            DateTime end = new DateTime(2010, 9, 7);

            OptimizationRunner runner = new OptimizationRunner();
            List<OptimizationRunner.PConstraint> constraints = new List<OptimizationRunner.PConstraint>();
            // Add Sector Constraints 
            constraints.Add(new OptimizationRunner.PConstraint(0.11, 0.19, new string[] { "WEAT LN Equity", "CORN LN Equity", "DBA US Equity" }));  // Agriculture
            constraints.Add(new OptimizationRunner.PConstraint(0.65, 0.75, new string[] { "USO US Equity", "OIL US Equity", "UNG US Equity", "DBE US Equity"}));  // Energy
            constraints.Add(new OptimizationRunner.PConstraint(0.06, 0.13, new string[] { "JJC US Equity", "JJM US Equity", "DBB US Equity"}));  // Industrial Metals
            constraints.Add(new OptimizationRunner.PConstraint(0.03, 0.06, new string[] { "COW US Equity" }));  // Livestock
            constraints.Add(new OptimizationRunner.PConstraint(0.02, 0.04, new string[] { "GLD US Equity", "SLV US Equity", "DBP US Equity"}));  // Precious Metals

            DataTable outTable = runner.runMinVarBackTest(dTable, start, end, constraints);

            string tmpFileName = "tmpMinVarBTOnCommodityETF.csv";
            string expFileName = "..\\..\\Tests\\MinVarBTOnCommodityETF.csv";

            TALoaders.Utilities.saveDataTableToCSV(tmpFileName, outTable);
            FileAssert.AreEqual(expFileName, tmpFileName, "Optimization runner outTable with Constraints");
            File.Delete(tmpFileName);
        }

        [Test]
        [Category("Calculation")]
        public void runMinVarBTOnCommodityIx()
        {
            DataTable dTable = this.createTableFromCSV("CommodityIndexesInput.csv");

            DateTime start = new DateTime(2009, 1, 4);
            DateTime end = new DateTime(2010, 9, 7);

            OptimizationRunner runner = new OptimizationRunner();
            List<OptimizationRunner.PConstraint> constraints = new List<OptimizationRunner.PConstraint>();

            DataTable outTable = runner.runMinVarBackTest(dTable, start, end, constraints);

            string tmpFileName = "tmpMinVarBTCommodityIndexesInput.csv";
            string expFileName = "..\\..\\Tests\\MinVarBTCommodityIndexesInput.csv";

            TALoaders.Utilities.saveDataTableToCSV(tmpFileName, outTable);
            FileAssert.AreEqual(expFileName, tmpFileName, "Optimization runner outTable without Constraints");
            File.Delete(tmpFileName);
        }

        [Test]
        [Category("Calculation")]
        public void runMinVarBTOnCommoditySubIx()
        {
            DataTable dTable = this.createTableFromCSV("CommoditySubIndexesInput.csv");

            DateTime start = new DateTime(2009, 1, 4);
            DateTime end = new DateTime(2010, 9, 7);

            OptimizationRunner runner = new OptimizationRunner();
            List<OptimizationRunner.PConstraint> constraints = new List<OptimizationRunner.PConstraint>();
            // Add Sector Constraints 
            constraints.Add(new OptimizationRunner.PConstraint(0.11, 0.19, new string[] { "SPGSWT Index" /* Wheat */, "SPGCCN Index" /* Corn */, "SPGCSB Index" /* Sugar */}));  // Agriculture
            constraints.Add(new OptimizationRunner.PConstraint(0.65, 0.75, new string[] { "SPGCCL Index" /* Crude */, "SPGCBR Index" /* Brent */, "SPGCGO Index" /* GasOil */, "SPGCNG Index" /* NatGas */}));  // Energy
            constraints.Add(new OptimizationRunner.PConstraint(0.06, 0.13, new string[] { "SPGCIC Index" /* Copper */, "SPGCIA Index" /* Alluminium */}));  // Industrial Metals
            constraints.Add(new OptimizationRunner.PConstraint(0.03, 0.06, new string[] { "SPGCLV Index" /* LiveStock */}));  // Livestock
            constraints.Add(new OptimizationRunner.PConstraint(0.02, 0.04, new string[] { "SPGCGC Index" /* Gold */, "SPGCSB Index" /* Silver */}));  // Precious Metals

            DataTable outTable = runner.runMinVarBackTest(dTable, start, end, constraints);

            string tmpFileName = "tmpMinVarBTCommoditySubIndexes.csv";
            string expFileName = "..\\..\\Tests\\MinVarBTCommoditySubIndexes.csv";

            TALoaders.Utilities.saveDataTableToCSV(tmpFileName, outTable);
            FileAssert.AreEqual(expFileName, tmpFileName, "Optimization runner outTable with Constraints");
            File.Delete(tmpFileName);
        }

        [Test]
        [Category("Calculation")]
        public void runMinVarBTShortNoConstr()
        {
            DataTable dTable = this.createTableFromCSV("CommodityETFs.csv");

            DateTime start = new DateTime(2009, 12, 30);
            DateTime end = new DateTime(2010, 9, 7);

            OptimizationRunner runner = new OptimizationRunner();
            List<OptimizationRunner.PConstraint> constraints = new List<OptimizationRunner.PConstraint>();

            DataTable outTable = runner.runMinVarBackTest(dTable, start, end, constraints);

            string tmpFileName = "tmpMinVarBTShortNoConstr.csv";
            string expFileName = "..\\..\\Tests\\MinVarBTShortNoConstr.csv";

            TALoaders.Utilities.saveDataTableToCSV(tmpFileName, outTable);
            FileAssert.AreEqual(expFileName, tmpFileName, "Optimization runner outTable with Constraints");
            File.Delete(tmpFileName);
        }

        private DataTable createTableFromCSV(string csvTableName)
        {
            CachedDownloader.clearCache();
            string cacheFile = "..\\..\\Tests\\TestDownloaderCache.cache";
            CachedDownloader.openCacheFromFile(cacheFile);

            DataTable dTable = this.createEmptyDataTable();
            string csvFileName = "..\\..\\Tests\\" + csvTableName;
            Utilities.loadCSVToDataTable(csvFileName, ref dTable);
            return dTable;
        }

        private DataTable createEmptyDataTable()
        {
            DataTable dTable = new DataTable();
            dTable.Columns.Add(PortfolioAllocatorWindow.LOADER_COL, typeof(Loader));
            dTable.Columns.Add(PortfolioAllocatorWindow.TICKER_COL, typeof(string));
            dTable.Columns.Add(PortfolioAllocatorWindow.EXP_RET_COL, typeof(double));
            dTable.Columns.Add(PortfolioAllocatorWindow.MIN_WEIGHT_COL, typeof(double));
            dTable.Columns.Add(PortfolioAllocatorWindow.MAX_WEIGHT_COL, typeof(double));
            return dTable;
        }

    }
}
